/**
 * ext-shapes.js
 *
 * @license MIT
 *
 * @copyright 2010 Christian Tzurcanu, 2010 Alexis Deveria
 *
 */
const ROOM_MAP_IDS = {
    escalator: 'COMMON_ESCALATOR',
    elevator: 'COMMON_ELEVATOR',
    stairs: 'COMMON_STAIRS',
    doubleDoors: 'COMMON_DOUBLE_DOOR',
    singleDoor: 'COMMON_SINGLE_DOOR'
}
export default {
    name: 'shapes',
    async init({ $, importLocale }) {
        const strings = await importLocale()
        const svgEditor = this
        const canv = svgEditor.canvas
        const svgroot = canv.getRootElem()
        let lastBBox = {}

        // This populates the category list
        const { categories } = strings

        const library = {
            basic: {
                data: {
                    /**
                     * 自定义
                     */
                    // 扶梯
                    escalator:
                        'M338.7392 546.640457v-225.28c0-32.182857 11.0592-69.368686 57.344-85.460114-33.206857-18.139429-56.32-53.306514-56.32-93.535086a106.671543 106.671543 0 0 1 106.583771-106.613028 106.671543 106.671543 0 0 1 51.287772 200.118857c13.077943 4.037486 24.137143 11.088457 33.206857 20.128914 16.091429 16.091429 25.161143 38.209829 25.161143 66.384457v28.145372l-217.263543 196.110628z m111.645257-278.557257h-5.032228c-58.338743 0.994743-66.384457 26.126629-66.384458 52.282514v134.7584l135.753143-123.6992v-10.064457c0-17.086171-4.008229-29.140114-13.048685-37.185828-9.069714-11.088457-27.150629-16.091429-51.287772-16.091429z m-4.037486-193.097143a66.9696 66.9696 0 0 0-66.3552 66.3552A66.9696 66.9696 0 0 0 446.346971 207.725714a66.9696 66.9696 0 0 0 66.384458-66.384457 66.9696 66.9696 0 0 0-66.384458-66.3552zM287.451429 1010.249143H88.327314c-36.220343 0-64.365714-29.169371-64.365714-64.365714v-96.548572c0-36.191086 29.169371-64.365714 64.365714-64.365714H247.222857c32.182857 0 53.306514-7.021714 70.392686-24.137143L853.664914 224.811886c34.2016-34.172343 62.346971-40.228571 109.626515-40.228572h147.836342c3.013486 0 6.026971 0 9.069715-0.994743l23.113143-3.013485v8.045714c26.155886 8.045714 44.266057 33.1776 44.266057 61.352229v96.548571c0 36.191086-29.169371 64.365714-64.365715 64.365714-3.013486 0-7.050971 0-11.0592-1.024H994.450286c-14.101943 0-16.091429 1.024-23.1424 8.045715L440.32 947.931429c-43.242057 39.204571-98.567314 62.346971-152.868571 62.346971z m-194.091886-41.252572h195.086628c44.266057 0 89.526857-19.075657 123.728458-51.258514l532.011885-530.0224c16.091429-14.072686 27.150629-18.110171 50.293029-18.110171h123.6992c2.018743 0 4.008229 1.024 5.032228 1.024a24.458971 24.458971 0 0 0 24.137143-24.137143V250.967771a24.458971 24.458971 0 0 0-24.137143-24.137142h-20.128914V225.865143h-139.790628c-43.242057 0-59.333486 5.032229-81.451886 28.145371L345.790171 789.065143c-24.137143 24.137143-56.32 36.191086-98.567314 36.191086H88.327314a24.458971 24.458971 0 0 0-24.137143 24.137142v95.553829c0 13.077943 11.0592 24.137143 24.137143 24.137143h5.032229z m126.683428-215.186285h-151.844571v-3.013486c-26.126629-9.069714-45.2608-33.206857-45.2608-62.376229a64.365714 64.365714 0 0 1 44.266057-61.352228v-1.989486l19.104914-2.048h111.645258c24.137143 0 24.137143 0 34.172342-10.0352l132.768915-132.739657h-0.994743l35.196343-34.230857 177.005714-172.968229 192.073143-191.049143c38.239086-39.233829 100.586057-56.349257 144.822857-56.349257h210.212571c36.191086 0 64.365714 29.169371 64.365715 64.365715 0 36.220343-29.169371 64.365714-64.365715 64.365714-4.037486 0-8.045714 0-12.0832-0.994743h-185.051428c-37.215086 0-52.282514 3.013486-68.373943 19.104914L312.583314 717.6192c-25.131886 24.137143-53.277257 36.220343-92.511085 36.220343zM108.456229 713.581714h111.645257c28.145371 0 47.279543-7.050971 64.365714-24.137143L829.527771 144.354743c29.169371-29.140114 58.338743-31.158857 96.548572-31.158857h192.1024c2.018743 0 4.008229 0.994743 6.026971 0.994743a24.458971 24.458971 0 0 0 24.137143-24.137143 24.458971 24.458971 0 0 0-24.137143-24.137143h-211.207314c-35.196343 0-86.484114 14.072686-116.648229 44.266057l-191.0784 191.049143-177.005714 172.997486-165.946514 165.946514c-21.123657 21.123657-28.174629 22.147657-62.376229 22.147657H109.450971l-20.128914 0.994743a24.458971 24.458971 0 0 0-24.137143 24.137143c0 13.077943 11.0592 24.137143 24.137143 24.137143l19.104914 2.018742z',
                    // 电梯
                    elevator:
                        'M494.344828 247.172414H211.862069v706.206896h282.482759V247.172414z m35.310344 0v706.206896h282.482759V247.172414h-282.482759zM176.551724 971.034483v-741.517242a17.655172 17.655172 0 0 1 17.655173-17.655172h635.586206a17.655172 17.655172 0 0 1 17.655173 17.655172V988.689655h141.241379V35.310345H35.310345v953.37931h141.241379v-17.655172z m741.517242-494.344828a17.655172 17.655172 0 1 1-35.310345 0 17.655172 17.655172 0 0 1 35.310345 0z m0 70.62069a17.655172 17.655172 0 1 1-35.310345 0 17.655172 17.655172 0 0 1 35.310345 0zM211.862069 988.689655v17.655173a17.655172 17.655172 0 0 1-17.655172 17.655172h-176.551725a17.655172 17.655172 0 0 1-17.655172-17.655172V17.655172A17.655172 17.655172 0 0 1 17.655172 0h988.689656a17.655172 17.655172 0 0 1 17.655172 17.655172v988.689656a17.655172 17.655172 0 0 1-17.655172 17.655172h-176.551725a17.655172 17.655172 0 0 1-17.655172-17.655172V988.689655H211.862069z m158.896552-840.139034l-22.810483 22.845793a17.655172 17.655172 0 1 1-24.999724-24.999724l35.310345-35.310345a17.655172 17.655172 0 0 1 24.999724 0l35.310345 35.310345a17.655172 17.655172 0 0 1-24.999725 24.999724l-22.810482-22.845793z m269.982896-37.428966a17.655172 17.655172 0 0 1 24.999724 24.964414l-35.310344 35.310345a17.655172 17.655172 0 0 1-24.999725 0l-35.310344-35.310345a17.655172 17.655172 0 0 1 24.999724-24.999724l22.810482 22.845793 22.810483-22.845793z',
                    // 楼梯
                    stairs:
                        'M825.856 37.376h179.2c10.24 0 18.432-8.192 18.432-18.432S1015.296 0.512 1005.056 0.512H814.08c-0.512 0-1.024 0-2.048 0.512-0.512 0-1.024 0.512-1.536 0.512-0.512 0-1.536 0.512-2.048 1.024-0.512 0-0.512 0.512-1.024 0.512-1.024 0.512-1.536 1.024-2.56 1.536L69.632 617.472c-7.68 6.656-8.704 18.432-2.56 26.112l1.024 1.024c6.656 7.68 18.432 8.704 26.112 2.56l25.088-20.992v225.792H0V1024h1024v-171.52H149.504v-251.392l141.312-117.76v229.888H175.104v139.776H1024V154.112h-174.08v139.776h-25.6V38.912l1.536-1.536zM322.048 712.704V457.216l141.312-117.76v233.472H347.136v139.776h-25.088z m172.032-139.776V313.856L619.52 209.408v223.744h-99.84v139.776h-25.6zM793.6 293.376h-117.76v139.776h-25.6V183.808l143.36-119.296v228.864z',
                    // 双开门
                    doubleDoors:
                        'M197.2224 126.549333v667.118934h-59.733333v143.752533H8.533333a8.533333 8.533333 0 1 1 0-17.066667h111.889067V793.6H8.533333a8.533333 8.533333 0 0 1 0-17.066667h120.4224V102.468267c202.376533 0 349.184 166.8608 381.610667 404.8384C542.958933 269.312 689.7664 102.4 892.177067 102.4v674.065067h120.4224a8.533333 8.533333 0 0 1 0 17.066666h-111.889067v126.754134h111.889067a8.533333 8.533333 0 0 1 0 17.066666h-128.955734V793.6h-59.733333V126.464C641.979733 164.846933 520.9088 356.864 520.9088 608.699733V793.6h-3.618133v0.068267h-17.066667V608.750933c0-251.835733-121.053867-443.8528-303.0016-482.2016z m677.888 1.450667h-34.133333v648.533333h34.133333v-648.533333z m-729.088 0.068267v648.533333h34.133333v-648.533333h-34.133333z',
                    // 单开门
                    singleDoor:
                        'M810.666667 907.52V759.466667c0-356.181333-257.467733-638.805333-597.333334-647.441067V947.2H17.066667a8.533333 8.533333 0 1 1 0-17.066667h179.2v-153.6H17.066667a8.533333 8.533333 0 1 1 0-17.066666h102.7072v-665.6H213.333333v1.0752c355.720533 8.704 614.4 305.937067 614.4 664.5248H1006.933333a8.533333 8.533333 0 1 1 0 17.066666H827.733333v153.6H1006.933333a8.533333 8.533333 0 1 1 0 17.066667H810.666667v-39.68z m-614.4-148.053333v-648.533334H136.840533v648.533334H196.266667z'
                },
                buttons: []
            }
        }

        const modeId = 'shapelib'
        const startClientPos = {}

        let currentD, curShapeId, curShape, startX, startY
        let curLib = library.basic

        /**
         *
         * @returns {void}
         */
        function loadIcons() {
            $('#shape_buttons')
                .empty()
                .append(curLib.buttons)
        }

        /**
         * @typedef {PlainObject} module:Extension.Shapes.Shapes
         * @property {PlainObject<string, string>} data
         * @property {Integer} [size]
         * @property {boolean} [fill]
         */

        /**
         * @param {string|"basic"} cat Category ID
         * @param {module:Extension.Shapes.Shapes} shapes
         * @returns {void}
         */
        function makeButtons(cat, shapes) {
            const size = curLib.size || 300
            const fill = curLib.fill || false
            const off = size * 0.05
            const vb = [-off, -off, size + off * 2, size + off * 2].join(' ')
            const stroke = fill ? 0 : size / 30
            const shapeIcon = new DOMParser().parseFromString(
                '<svg xmlns="http://www.w3.org/2000/svg">' +
                    '<svg viewBox="' +
                    vb +
                    '">' +
                    '<path fill="' +
                    (fill ? '#333' : 'none') +
                    '" stroke="#000" stroke-width="' +
                    stroke +
                    '" /></svg></svg>',
                'text/xml'
            )

            const width = 24
            const height = 24
            shapeIcon.documentElement.setAttribute('width', width)
            shapeIcon.documentElement.setAttribute('height', height)
            const svgElem = $(
                document.importNode(shapeIcon.documentElement, true)
            )

            const { data } = shapes

            curLib.buttons = Object.entries(data).map(([id, pathD]) => {
                const icon = svgElem.clone()
                icon.find('path').attr('d', pathD)

                const iconBtn = icon
                    .wrap(
                        '<div class="tool_button" shape="' +
                            ROOM_MAP_IDS[id] +
                            '">'
                    )
                    .parent()
                    .attr({
                        id: modeId + '_' + id,
                        title: id
                    })
                // Store for later use
                return iconBtn[0]
            })
        }

        /**
         * @param {string|"basic"} catId
         * @returns {void}
         */
        function loadLibrary(catId) {
            const lib = library[catId]

            if (!lib) {
                $('#shape_buttons').html(strings.loading)
                $.getJSON(
                    svgEditor.curConfig.extIconsPath +
                        'shapelib/' +
                        catId +
                        '.json',
                    function(result) {
                        curLib = library[catId] = {
                            data: result.data,
                            size: result.size,
                            fill: result.fill
                        }
                        makeButtons(catId, result)
                        loadIcons()
                    }
                )
                return
            }
            curLib = lib
            if (!lib.buttons.length) {
                makeButtons(catId, lib)
            }
            loadIcons()
        }
        const buttons = [
            {
                id: 'tool_shapelib',
                icon: svgEditor.curConfig.extIconsPath + 'shapes.png',
                type: 'mode_flyout', // _flyout
                position: 6,
                events: {
                    click() {
                        canv.setMode(modeId)
                    }
                }
            }
        ]

        return {
            svgicons: svgEditor.curConfig.extIconsPath + 'ext-shapes.xml',
            buttons: strings.buttons.map((button, i) => {
                return Object.assign(buttons[i], button)
            }),
            callback() {
                $('<style>')
                    .text(
                        `
          #shape_buttons {
            overflow: auto;
            width: 180px;
            max-height: 300px;
            display: table-cell;
            vertical-align: middle;
          }
          #shape_cats {
            min-width: 110px;
            display: table-cell;
            vertical-align: middle;
            height: 300px;
          }
          #shape_cats > div {
            line-height: 1em;
            padding: .5em;
            border:1px solid #B0B0B0;
            background: #E8E8E8;
            margin-bottom: -1px;
          }
          #shape_cats div:hover {
            background: #FFFFCC;
          }
          #shape_cats div.current {
            font-weight: bold;
          }
        `
                    )
                    .appendTo('head')

                const btnDiv = $('<div id="shape_buttons">')
                $('#tools_shapelib > *').wrapAll(btnDiv)
                const shower = $('#tools_shapelib_show')

                loadLibrary('basic')

                // Do mouseup on parent element rather than each button
                $('#shape_buttons').mouseup(function(evt) {
                    canv.clearSelection('')

                    const btn = $(evt.target).closest('div.tool_button')

                    if (!btn.length) {
                        $('#tools_left .current-tool').removeClass(
                            'current-tool'
                        )
                        canv.setMode('select')
                        $('#styleoverrides').text(`
                            #svgcanvas svg * {
                            cursor: move;
                            pointer-events: all;
                            }
                            #svgcanvas svg {
                            cursor: default;
                            }
                        `)
                        return
                    }

                    const copy = btn.children().clone()
                    shower.children(':not(.flyout_arrow_horiz)').remove()
                    shower
                        .append(copy)
                        .attr('data-curopt', '#' + btn[0].id) // This sets the current mode
                        .mouseup()

                    // 设置形状样式
                    canv.setColor('stroke', '#999')
                    canv.setColor('fill', '#999')
                    canv.setStrokeWidth(2)

                    canv.setMode(modeId)

                    curShapeId = btn[0].id.substr((modeId + '_').length)
                    currentD = curLib.data[curShapeId]

                    $('.tools_flyout').fadeOut()

                    $('#tools_left .tools-item').removeClass('current-tool')
                    let shapeId = $(evt.target).attr('shape')
                    $('#' + shapeId).addClass('current-tool')
                })

                /**
                 * 不需要这么多
                 */
                // const shapeCats = $('<div id="shape_cats">')

                // let catStr = ''
                // $.each(categories, function(id, label) {
                //     catStr += '<div data-cat=' + id + '>' + label + '</div>'
                // })

                // shapeCats
                //     .html(catStr)
                //     .children()
                //     .bind('mouseup', function() {
                //         const catlink = $(this)
                //         catlink.siblings().removeClass('current')
                //         catlink.addClass('current')

                //         loadLibrary(catlink.attr('data-cat'))
                //         // Get stuff
                //         return false
                //     })

                // shapeCats
                //     .children()
                //     .eq(0)
                //     .addClass('current')

                // $('#tools_shapelib').append(shapeCats)

                shower.mouseup(function() {
                    canv.setMode(currentD ? modeId : 'select')
                })
                $('#tool_shapelib').remove()

                const h = $('#tools_shapelib').height()
                $('#tools_shapelib').css({
                    'margin-top': -(h / 2 - 15),
                    'margin-left': 3
                })

                $('#tools_left').append($('#tools_shapelib'))
                /**
                 * 不需要
                 */
                // Now add shape categories from locale
                // const cats = {}
                // Object.entries(categories).forEach(([o, categoryName]) => {
                //     cats['#shape_cats [data-cat="' + o + '"]'] = categoryName
                // })
                // this.setStrings('content', cats)
            },
            mouseDown(opts) {
                const mode = canv.getMode()
                if (mode !== modeId) {
                    return undefined
                }

                startX = opts.start_x
                const x = startX
                startY = opts.start_y
                const y = startY
                const curStyle = canv.getStyle()

                startClientPos.x = opts.event.clientX
                startClientPos.y = opts.event.clientY

                curShape = canv.addSVGElementFromJson({
                    element: 'path',
                    curStyles: true,
                    attr: {
                        d: currentD,
                        id: canv.getNextId(),
                        opacity: curStyle.opacity / 2,
                        style: 'pointer-events:none'
                    }
                })

                // Make sure shape uses absolute values
                if (/[a-z]/.test(currentD)) {
                    currentD = curLib.data[
                        curShapeId
                    ] = canv.pathActions.convertPath(curShape)
                    curShape.setAttribute('d', currentD)
                    canv.pathActions.fixEnd(curShape)
                }
                curShape.setAttribute(
                    'transform',
                    'translate(' +
                        x +
                        ',' +
                        y +
                        ') scale(0.005) translate(' +
                        -x +
                        ',' +
                        -y +
                        ')'
                )

                canv.recalculateDimensions(curShape)

                /* const tlist = */ canv.getTransformList(curShape)

                lastBBox = curShape.getBBox()

                return {
                    started: true
                }
            },
            mouseMove(opts) {
                const mode = canv.getMode()
                if (mode !== modeId) {
                    return
                }

                const zoom = canv.getZoom()
                const evt = opts.event

                const x = opts.mouse_x / zoom
                const y = opts.mouse_y / zoom

                const tlist = canv.getTransformList(curShape),
                    box = curShape.getBBox(),
                    left = box.x,
                    top = box.y
                // {width, height} = box,
                // const dx = (x - startX), dy = (y - startY);

                const newbox = {
                    x: Math.min(startX, x),
                    y: Math.min(startY, y),
                    width: Math.abs(x - startX),
                    height: Math.abs(y - startY)
                }

                /*
        // This is currently serving no purpose, so commenting out
        let sy = height ? (height + dy) / height : 1,
          sx = width ? (width + dx) / width : 1;
        */

                let sx = newbox.width / lastBBox.width || 1
                let sy = newbox.height / lastBBox.height || 1

                // Not perfect, but mostly works...
                let tx = 0
                if (x < startX) {
                    tx = lastBBox.width
                }
                let ty = 0
                if (y < startY) {
                    ty = lastBBox.height
                }

                // update the transform list with translate,scale,translate
                const translateOrigin = svgroot.createSVGTransform(),
                    scale = svgroot.createSVGTransform(),
                    translateBack = svgroot.createSVGTransform()

                translateOrigin.setTranslate(-(left + tx), -(top + ty))
                if (!evt.shiftKey) {
                    const max = Math.min(Math.abs(sx), Math.abs(sy))

                    sx = max * (sx < 0 ? -1 : 1)
                    sy = max * (sy < 0 ? -1 : 1)
                }
                scale.setScale(sx, sy)

                translateBack.setTranslate(left + tx, top + ty)
                tlist.appendItem(translateBack)
                tlist.appendItem(scale)
                tlist.appendItem(translateOrigin)

                canv.recalculateDimensions(curShape)

                lastBBox = curShape.getBBox()
            },
            mouseUp(opts) {
                const mode = canv.getMode()
                if (mode !== modeId) {
                    return undefined
                }

                const keepObject =
                    opts.event.clientX !== startClientPos.x &&
                    opts.event.clientY !== startClientPos.y

                return {
                    keep: keepObject,
                    element: curShape,
                    started: false
                }
            }
        }
    }
}
